#include <fs.h>
#include <ipc.h>
#include "vga.h"

unsigned short *vidmem = (unsigned short *)0xC00B8000;
char attrib = 0x07;
int csr_x = 0, csr_y = 0;
unsigned int scr_h = 25;
unsigned int scr_w = 80;

void init_vga()
{
	struct vbe_controller_info vbe_info;
	void *buffer = (void *)v86_buffer();
	registers v86r;
	v86r.eax = 0x4f00;
	v86r.v86es = 0x0;
	v86r.edi = (unsigned int) buffer;

	unsigned int i = v86int(0x10,&v86r);
	memcopy(&vbe_info, buffer, sizeof(struct vbe_controller_info));
	unsigned int offset = (unsigned int)&vbe_info - (unsigned int)buffer;
	printf("Returned %x!",i);
	printf("\neax:%x ",v86r.eax);
	printf(vbe_info.signature);
	printf("\n %x \n", vbe_info.VideoModesPtr);
	unsigned short *modes = (unsigned short *)vbe_info.VideoModesPtr+offset;
	struct vbe_mode_info vbe_mode;
	for (i=0; modes[i]!=0xFFFF; i++)
	{
		printf("\n %x ", modes[i]);
		v86r.eax = 0x4f01;
		v86r.v86es = 0x0;
		v86r.ecx = modes[i];
		v86r.edi = (unsigned int) buffer;
		v86int(0x10,&v86r);
		memcopy(&vbe_mode, buffer, sizeof(struct vbe_mode_info));
		printf(" %dx%dx%d", vbe_mode.Xres, vbe_mode.Yres, vbe_mode.bpp);
	}
	
	v86r.eax = 0x4f02;
	v86r.ebx = 0x144;
	v86int(0x10,&v86r);
}

int video_num2str(unsigned int num, char *str, int base)
{
	int i = 0;
	unsigned int n;
	char tmp[64];
	while(num>0)
	{
		n = num%base;
		if (n<10)
			tmp[i++] = (char)((int)'0'+n);
		else
			tmp[i++] = (char)((int)'A'+(n-10));
		num /= base;
	}
	i--;
	int j = 0;
	while(i>=0)
		str[j++] = tmp[i--];
	str[j] = '\0';
	return j;
}

void video_move_csr()
{
	unsigned int i = csr_y * scr_w + csr_x;
	
	outb(0x3D4, 14);
	outb(0x3D5, i >> 8);
	outb(0x3D4, 15);
	outb(0x3D5, i);
}

void video_putch(char c, int pos)
{
	vidmem[pos++] = c | (attrib<<8);
}

void video_scroll()
{
	if(csr_y >= scr_h)
	{
		int i;
		for(i=0; i<(scr_h-1)*scr_w; i++)
			vidmem[i] = vidmem[i+scr_w];
		for(i=(scr_h-1)*scr_w;i<scr_h*scr_w;i++)
			video_putch(' ',i);
		csr_y=scr_h-1;
	}
	
}
void video_printf(unsigned char *str, ...)
{
	int i;
	va_list args;
	va_start(args,str);
	unsigned char buf[255];
	unsigned int num;
	while(*str != '\0')
	{

		i = (scr_w*csr_y +csr_x);
		if(*str == '%')
		{
			str++;
			if(*str == 'd' || *str == 'i')
			{
				num = va_arg(args, unsigned int);
				video_num2str(num,buf,10);
				video_printf(buf);
			}
			else if(*str == 'x')
			{
				num = va_arg(args, unsigned int);
				video_num2str(num,buf,16);
				video_printf("0x");
				video_printf(buf);
			}
			else if(*str == 'o')
			{
				num = va_arg(args, unsigned int);
				video_num2str(num,buf,8);
				video_printf(buf);
				video_printf("o");
			}
			else if(*str == 'b')
			{
				num = va_arg(args, unsigned int);
				video_num2str(num,buf,2);
				video_printf(buf);
				video_printf("b");
			}
			else if(*str == 'c')
			{
				unsigned char ch = va_arg(args, unsigned char);
				video_printf(&ch);
			}
			else if(*str == 's')
			{
				video_printf(va_arg(args, char*));
			}
		}
		else if(*str == '\n')
		{
			csr_x = 0;
			csr_y++;
		}
		else if(*str >= ' ')
		{
			video_putch(*str,i);
			csr_x++;
		}
		if(csr_x >= scr_w)
		{
			csr_x = 0;
			csr_y++;
		}
		video_scroll();
		video_move_csr();
		str++;
	}
	va_end();
}


void screen_print(unsigned int signum, unsigned int sender)
{
	struct write_msg *message = (struct write_msg *)valloc(sizeof(struct write_msg));
	getmsg(message);
	message->zero = '\0';
	video_printf(message->data);
	signal(sender, SIG_ACK, 0);
	free(message);
}

char lipsum[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc \
in tellus leo. In eget pretium nulla. Ut posuere tortor sed nunc consequat ut rut \
rum libero rhoncus. Nam quis nunc nisi. Nam accumsan vehicula quam, nec lacinia\
 lacus feugiat at. In elit diam, accumsan vitae congue vitae, suscipit ac odio.\
 Nam eget tortor fringilla urna dapibus cursus. Praesent sit amet leo ut orci i\
aculis molestie. Class aptent taciti sociosqu ad litora torquent per conubia no\
stra, per inceptos himenaeos. Mauris volutpat sem ut neque fringilla vel cursus\
 turpis consectetur. Vivamus ut arcu ipsum. Ut blandit ornare tristique. Sed et\
 purus magna, a condimentum arcu. Mauris quis sem justo, quis gravida enim. Lor\
em ipsum dolor sit amet, consectetur adipiscing elit. Fusce ornare, diam a pret\
ium sollicitudin, arcu leo faucibus arcu, at consectetur ipsum sapien ut enim. \
Mauris vitae enim lorem, volutpat eleifend orci. Maecenas ut ultrices est. \n\
\n\
Mauris sollicitudin vestibulum dui, id tincidunt velit dignissim non. In at qua\
m purus. Nulla tincidunt neque in mauris dictum aliquam. Nunc eget metus a eros\
 tristique accumsan. Vivamus felis orci, condimentum eu condimentum pharetra, p\
ulvinar non ante. Sed ultrices, magna adipiscing tristique mollis, ipsum nisi d\
apibus eros, ac feugiat odio ante eu ipsum. Praesent et tincidunt purus. Intege\
r tempus justo facilisis lorem blandit congue. In hac habitasse platea dictumst\
. Donec in sem libero. Donec commodo, ante vitae vestibulum ultricies, quam qua\
m ultrices erat, at gravida leo urna ut sem. Duis a nibh facilisis ante hendrer\
it elementum nec id purus. Proin in magna lacus. Cras dignissim orci at mauris \
tincidunt porttitor. Vestibulum aliquam, ligula non pharetra laoreet, neque aug\
ue fringilla ligula, rutrum interdum metus velit vel est. Pellentesque placerat\
tempus dui at blandit.";

void read_screen(unsigned int signum, unsigned int sender)
{
	
	struct read_msg *msg = (struct read_msg *)valloc(sizeof(struct read_msg));
	getmsg(msg);
	memcopy(&msg->data, (void *)((unsigned int)lipsum + msg->offset), msg->length);
	signal(sender, SIG_ACK, 0);
	free(msg);
	done();
}


int main(unsigned int arg)
{
	register_event_handler(SIG_WRITE, &screen_print);
	register_event_handler(SIG_READ, &read_screen);
//	init_vga();
//	for(;;)
//	{
//		unsigned char *vidmem = 0xC00B8000;
//		vidmem[0] = '-';
//		vidmem[1] = 0x7;
//	}
	done();
}
